iT邦幫忙

2024 iThome 鐵人賽

DAY 4
0
Security

你的程式真的安全嗎?從資安的角度做 code review系列 第 9

C - weak crypto algorithm (不安全的密碼術:演算法使用方式脆弱)

  • 分享至 

  • xImage
  •  

下方程式碼片段全部都是擷取自 Secure Code Warrior 線上安全程式培訓平台,因為練習互動時的題目多半不會只有單一個檔案,可能涉及多個檔案、資料夾及多處地方修改,因此我的文章主要是針對最主要的區塊做修改及說明,若有不好理解的地方非常抱歉也還請見諒,也可以實際上去 Secure Code Warrior 玩玩看,搭配著互動,會更有感的學習哦~

C - weak crypto algorithm (不安全的密碼術:演算法使用方式脆弱)

  • 形成原因:使用弱或過時的演算法來保護敏感資料
  • 後果:攻擊者透過暴力破解或是解密工具破解弱密碼得到敏感資訊
  • 解決方法:
    • 識別需保護的敏感資料
    • 使用強演算法和強金鑰加密資料
    • 建立金鑰和密碼管理系統
    • 在雜湊時加鹽

第1題

錯誤區塊

EVP_EncryptInit( e_ctx, EVP_aes_128_ccm(), (const unsigned char*)key.c_str(), iv );
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台
AES aesText( text );
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

解釋:高階加密標準(AES-128) 演算法不是密碼保護的最佳選擇。密碼保護必須使用強大的加密,而不是區塊加密。 此外,AES CCM 模式也不是AES演算法的最佳方法,它僅用於加密一些機密資料(如私人簡訊)。

主要修正方法

  1. 把ccm改成gcm
  2. 使用Argon2 雜湊函式,修改scrambler.cpp,改成以下
#include <iostream>
#include "argon2.h"
#include "Scrambler.h"

std::string Scrambler::cipher( const std::string text, const std::string salt )
{
	const int outLength = 32;
	unsigned char out[ outLength ];
	const int encodedLength = 128;
	char encoded[ encodedLength ];
	argon2_type type = Argon2_i;

	int result = argon2_hash( 2, 1 << 16, 1,
		text.c_str(), text.length(),
		salt.c_str(), salt.length(),
		out, outLength,
		encoded, encodedLength,
		type, ARGON2_VERSION_NUMBER);

	if( result != ARGON2_OK )
	{
		std::cout << "Error: " << argon2_error_message( result ) << std::endl;
		exit(1);
	}
	unsigned char hexout[ outLength * 2 + 4 ];
	for( int i = 0; i < outLength; i++ )
	{
		sprintf((char*)(hexout + i * 2), "%02x", out[ i ] );
	}
	return std::string( reinterpret_cast< const char* >( hexout ) );
}
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

解釋:
Argon2是一個強大的雜湊函式,可用於雜湊密碼、金鑰或其他機密資料。Argon2還是一個記憶體硬函式,這意味它比其他雜湊函式使用更多的記憶體。使用此雜湊函式,攻擊者不能使用GPU並行雜湊數百或數千個密碼。這大大增加了攻擊者破解密碼所需的時間。
此外,對於大多數需要認證加密的應用程式,AES GCM模式應被視為優於CCM。由於發生身份驗證,GCM不易受到位翻轉和其他可以針對計數器安裝的攻擊

第2題

錯誤區塊

byte digest[ CryptoPP::Weak::MD5::DIGESTSIZE ];

CryptoPP::Weak::MD5 hash;
hash.CalculateDigest( digest, (const byte*)word.c_str(), word.length() );

CryptoPP::HexEncoder encoder;
string encodedWord;

encoder.Attach( new CryptoPP::StringSink( encodedWord ) );
encoder.Put( digest, sizeof(digest) );
encoder.MessageEnd();

return encodedWord;
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

解釋:MD5被認為產生的雜湊密碼不安全

主要修正方法

把encode-controller整份檔案:

#include "encode-controller.hpp"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>

#include "../cryptopp810/md5.h"

using namespace std;

#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1

EncodeController::EncodeController()
{ }

string EncodeController::EncodeAlgorithm(string word)
{
  byte digest[ CryptoPP::Weak::MD5::DIGESTSIZE ];

  CryptoPP::Weak::MD5 hash;
  hash.CalculateDigest( digest, (const byte*)word.c_str(), word.length() );

  CryptoPP::HexEncoder encoder;
  string encodedWord;

  encoder.Attach( new CryptoPP::StringSink( encodedWord ) );
  encoder.Put( digest, sizeof(digest) );
  encoder.MessageEnd();

  return encodedWord;
}

bool EncodeController::VerifyPassword(string password, string encoded)
{
  bool status = false;
  
  string encodedPass = EncodeAlgorithm(password);

  if(encodedPass.compare(encoded)==0)
    status = true;

  return status;
}
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

改成:

#include "encode-controller.hpp"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <openssl/rand.h>
#include "../argon2/include/argon2.h"

#define HASHLEN 32
#define SALTLEN 16

EncodeController::EncodeController()
{ }

std::string EncodeController::EncodeAlgorithm(std::string word)
{
  std::string encodedWord;
  char * PWD = new char [word.length()+1];
  strncpy (PWD, word.c_str(), word.length()+1);
  uint8_t hash1[HASHLEN];
  uint8_t hash2[HASHLEN];

  uint8_t salt[SALTLEN];
  RAND_bytes(salt, SALTLEN);

  uint8_t *pwd = (uint8_t *)strdup(PWD);
  uint32_t pwdlen = strlen((char *)pwd);

  uint32_t t_cost = 2;            // 1-pass computation
  uint32_t m_cost = (1<<16);      // 64 mebibytes memory usage
  uint32_t parallelism = 1;       // number of threads and lanes

  // high-level API
  argon2i_hash_raw(t_cost, m_cost, parallelism, pwd, pwdlen, salt, SALTLEN, hash1, HASHLEN);

  free(pwd);
  delete [] PWD;

  for( int i=0; i<HASHLEN; ++i )
    encodedWord+=hash1[i];

  return encodedWord;
}

bool EncodeController::VerifyPassword(std::string password, std::string encoded)
{
  bool status = false;

  char * PWD = new char [password.length()+1];
  char * hashed = new char [encoded.length()+1];

  strncpy (PWD, password.c_str(), password.length()+1);
  strcpy (hashed, encoded.c_str(), encoded.length()+1);

  int vp = argon2i_verify(hashed, PWD, strlen(PWD));

  if(ARGON2_OK != vp) {
      printf("Error: %s\n", argon2_error_message(vp));
      exit(1);
  }
  else
    status = true;

  delete [] PWD;
  delete [] hashed;

  return status;
}
//程式碼片段擷取自 Secure Code Warrior 線上安全程式培訓平台

並刪除md5.cpp和md5.h兩個檔案

解釋:雜湊密碼的絕佳替代方案是使用Argon2演算法,因為它實現了防止GPU破解和側通道攻擊。
(我一開始選改成sha256和sha1的都跟我說是弱演算法)


上一篇
C - SQL injection(注入缺陷:SQL 注入)
下一篇
C - error details (資訊曝露:錯誤詳情)
系列文
你的程式真的安全嗎?從資安的角度做 code review25
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言